package com.sugon.controller.spare;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.cait.bpmsuite.api.bpmmodle.BPMProcessInstance;
import com.cait.bpmsuite.api.bpmmodle.BPMWorkItem;
import com.cait.service.rescenter.UserInfo;
import com.sugon.annotation.AutoLog;
import com.sugon.annotation.DataFilter;
import com.sugon.annotation.LimitSubmit;
import com.sugon.annotation.NonBusinessParamValid;
import com.sugon.dao.MaterialBaseDao;
import com.sugon.dao.MaterialRecordDao;
import com.sugon.entity.*;
import com.sugon.entity.dto.PickListDTO;
import com.sugon.entity.vo.SpareMaterialBaseApproveParam;
import com.sugon.modules.base.consts.BusModule;
import com.sugon.modules.sparepart.consts.MaterialBaseConst;
import com.sugon.modules.sparepart.consts.MaterialBaseProgress;
import com.sugon.modules.sparepart.model.vo.CommonApproveParamVO;
import com.sugon.modules.sparepart.model.vo.SparepartMaterialItemParam;
import com.sugon.modules.sparepart.service.ISparepartMaterialBaseManager;
import com.sugon.modules.sys.service.IResCenterAuthenticator;
import com.sugon.modules.utils.HttpUtil;
import com.sugon.modules.workflow.IWorkFlowManager;
import com.sugon.service.*;
import com.sugon.utils.*;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 备件领料单
 */
@Controller
@RequestMapping("spareMater")
public class SpareMaterController {

    @Autowired
    private MaterialBaseService materialBaseService;
    @Autowired
    private MaterialRecordService materialRecordService;
    @Resource
    private DevRepairRecordService devRepairRecordService;
    @Autowired
    private ISparepartMaterialBaseManager sparepartMaterialBaseManager;
    @Autowired
    private IResCenterAuthenticator resCenterAuthenticator;
    @Resource
    private MaterialBaseDao materialBaseDao;
    @Resource
    private MaterialRecordDao materialRecordDao;
    @Resource
    private IWorkFlowManager workFlowManager;
    @Resource
    private SysUserService userService;
    @Resource
    private SysOaProcessService oaProcessService;
    @Resource
    private SparePartConsumRecordService sparePartConsumRecordService;
    @Autowired
    private SysOaProcessService processService;
    @Resource
    private DevMaintenanceTicketService pmTicketService;

    /**
     * 查看、审核备件领料单
     * 1、根据workItemId找到对应的备件领料单ID,从而获取领料单和领料明细
     */
    @RequestMapping("/viewAudit")
    public String infoDetailByWorkItemId(HttpServletRequest request, HttpServletResponse response) {
        if (resCenterAuthenticator.checkIdentityToken(request, response)) {
            String identityToken = resCenterAuthenticator.getIdentityToken(request, response);
            Assert.notBlank(identityToken, "登录令牌不能为空！");
            UserInfo currentUser = resCenterAuthenticator.getUserByToken(identityToken);
            if (currentUser == null) {
                throw new UnknownAccountException(StrUtil.format("无效IdentityToken，获取用户信息失败！", identityToken));
            }
            //由于ERMS有自己的登录系统，需要重新登录下
            Subject subject = ShiroUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(currentUser.getLoginID(), "");
            subject.login(token);
            // 获取OA审批流程ID和审批工作项ID
            String workItemId = request.getParameter("workItemId");
            String procInstId = request.getParameter("procInstId");
            Assert.isFalse(StrUtil.isAllBlank(procInstId, workItemId), "目前只允许OA审批用到该页面");
            // 构建查询参数
            Map<String, String> paramMap = MapUtil.newHashMap();
            paramMap.put("procInstId", procInstId);
            paramMap.put("workItemId", workItemId);
            String queryParam = HttpUtil.buildQueryParam(paramMap);
            // 目前统一跳转到备件领料页
            return "/spare/sparematerialdetail.html" + queryParam;
        } else {
            // 获取完整的请求地址
            String redirectUrl = HttpUtil.getRequestPath(request);
            //生成认证代理地址并执行重定向跳转
            redirectUrl = resCenterAuthenticator.getLoginAgentUrlByRedrect(redirectUrl);
            return "redirect:" + redirectUrl;
        }
    }

    /**
     * 审核处理
     */
    @LimitSubmit(key = "spareMaterCheck:%s")
    @NonBusinessParamValid
    @RequestMapping("/check")
    @ResponseBody
    public String check(@Validated CommonApproveParamVO approveParam, BindingResult bindingResult) {
        String directUrl;
        // 获取领料单ID
        String id = approveParam.getId();
        // 校验下是否已添加备件
        List<MaterialRecordEntity> materialRecords = materialRecordService.queryByMater(id);
        Assert.notEmpty(materialRecords);
        // 校验该工作项是否已审核，如果已审核，那么根据审核情形，跳转到不同页面
        SysOaProcessEntity handledWorkItem = oaProcessService.queryByProcessWorkItemId(approveParam.getWorkItemId());
        if (handledWorkItem != null) {
            if (MaterialBaseConst.AUDIT_PASSED.equals(handledWorkItem.getState())) {
                // 重定向到下一流程
                directUrl = "/BPMClient/bpmdesktop/missionmanage/Missionredirect.jsf?workItemId=" + approveParam.getWorkItemId();
            } else {
                // 审核不通过，回退
                directUrl = "/BPMClient/bpmdesktop/missionmanage/Missionexecute.jsf?workitemId=" + approveParam.getWorkItemId() + "&rollback=true";
            }
        } else {
            directUrl = sparepartMaterialBaseManager.check(approveParam);
        }
        // 返回前端页面需要重定向的地址
        return resCenterAuthenticator.getLoginAgentUrlByRedrect(directUrl);
    }

    @NonBusinessParamValid
    @RequestMapping("/updateActualNum")
    @ResponseBody
    public R updateActualNum(@Validated SparepartMaterialItemParam param, BindingResult bindingResult) {
        // 校验领用明细ID是否合法
        MaterialRecordEntity entity = materialRecordService.queryObject(param.getId());
        if (entity == null) {
            return R.error("非法领用明细ID！");
        }
        // 实发数不得大于申请数
        if (param.getActualNum() > entity.getNum()) {
            return R.error("实发数不得大于申请数！");
        }
        entity.setActualNum(param.getActualNum());
        return materialRecordService.update(entity) > 0 ? R.ok("调整实发数成功！") : R.error("调整实发数失败，请稍后重试！");
    }

    /**
     * 审核处理
     */
    @RequestMapping("/logicDelete")
    @ResponseBody
    public R logicDelete(@RequestParam String itemId) {
        List<MaterialRecordEntity> itemList = materialRecordDao.listAllBaseItem(itemId);
        if (CollectionUtil.isEmpty(itemList) || itemList.size() < 2) {
            return R.error("删除失败，请确保备件领用申请列表中至少包含一条申请记录！");
        }
        // 逻辑删除指的是将delFlag字段置为空
        MaterialRecordEntity param = new MaterialRecordEntity();
        param.setId(itemId);
        param.setDelFlag(Constant.IS_DEL_INT);
        return materialRecordService.update(param) > 0 ? R.ok("删除成功！") : R.error("删除失败，请稍后重试！");
    }

    /**
     * 查看信息,两部分
     * 1、当前审核的进度
     * 2、领料单列表
     */
    @GetMapping("/loadSpareMaterialBaseList")
    @ResponseBody
    public R loadSpareMaterialBaseList(@RequestParam(value = "procInstId", required = false) String
                                               procInstId, @RequestParam(value = "workItemId", required = false) String workItemId) {
        Assert.isFalse(StrUtil.isAllBlank(procInstId, workItemId), "目前只允许OA审批用到该页面");
        // 工作项状态：默认为完成
        int workItemState = 5;
        if (StrUtil.isEmpty(procInstId)) {
            BPMWorkItem workItem = workFlowManager.getWorkItemById(workItemId);
            Assert.notNull(workItem, "非法流程工作项ID：{}！", workItemId);
            procInstId = workItem.getProcInstId();
            // 获取工作项状态
            workItemState = workItem.getState();
        }
        // 获取审核记录，需要处理第一次审核的场景
        List<SysOaProcessEntity> auditRecordList = materialBaseDao.queryAuditRecordByProcInstId(procInstId);
        if (auditRecordList == null) {
            auditRecordList = CollectionUtil.newArrayList();
        }
        // 设置领料列表
        List<MaterialRecordEntity> materialItems = null;
        PickListDTO pickListDTO = materialBaseDao.queryPickListByProcInstId(procInstId);
        if (pickListDTO != null) {
            materialItems = pickListDTO.getMaterialItems();
        } else {
            pickListDTO = new PickListDTO();
            pickListDTO.setId("");
            pickListDTO.setPickerName("");
            pickListDTO.setDeptName("");
            pickListDTO.setPurpose("");
            pickListDTO.setPickDate(DateUtil.date());
        }
        if (materialItems == null) {
            materialItems = CollectionUtil.newArrayList();
        }
        return R.ok().put("materialBase", pickListDTO).put("workItemState", workItemState).put("materialItems", materialItems).put("auditRecordList", Optional.ofNullable(auditRecordList).orElseGet(() -> new ArrayList<>()));
    }

    /**
     * 查看列表
     */
    @AutoLog(value = "列表查看", busModule = BusModule.LLD)
    @DataFilter(deptAlias = "mb.DEPT_ID", userAlias = "mb.PICKER")
    @RequestMapping("/list")
    @ResponseBody
    public R list(@RequestParam Map<String, Object> params) {
        // 开始时间
        String startTime = MapUtil.getStr(params, "startTime");
        if (StrUtil.isNotEmpty(startTime)) {
            params.put("startTime", startTime + " 0:00:00");
        }
        // 结束时间
        String endTime = MapUtil.getStr(params, "endTime");
        if (StrUtil.isNotEmpty(endTime)) {
            params.put("endTime", endTime + " 23:59:59");
        }

        //查询列表数据
        Query query = new Query(params);
        List<MaterialBaseEntity> materialBaseList = materialBaseService.queryList(query);
        int total = materialBaseService.queryTotal(query);
        PageUtils pageUtil = new PageUtils(materialBaseList, total, query.getLimit(), query.getPage());
        return R.ok().put("page", pageUtil);
    }

    /**
     * 查看信息
     */
    @RequestMapping("/info/{id}")
    @RequiresPermissions("spareMater:info")
    @ResponseBody
    public R info(@PathVariable("id") String id) {
        MaterialBaseEntity materialBase = materialBaseService.queryObject(id);

        return R.ok().put("materialBase", materialBase);
    }

    /**
     * 查看信息
     */
    @RequestMapping("/infoDetail/{id}")
    @ResponseBody
    public R infoDetail(@PathVariable("id") String id) {
        MaterialBaseEntity materialBase = materialBaseService.queryObjectDetail(id);
        return R.ok().put("materialBase", materialBase);
    }


    /**
     * 出库
     *
     * @param id
     * @return
     */
    @AutoLog(value = "出库", busModule = BusModule.LLD)
    @RequestMapping("/out/{id}")
    @RequiresPermissions("spareMater:out")
    @ResponseBody
    public R out(@PathVariable("id") String id) {
        // 校验领料单是否存在
        MaterialBaseEntity materialBase = materialBaseService.queryObject(id);
        if (materialBase == null) {
            return R.error("领料单不存在！");
        }
        // 校验是否可出库
        if (materialBase.getProgress() != MaterialBaseProgress.WAIT_OUTBOUND) {
            return R.error("只有处于待出库状态的领料单才可以执行出库操作！");
        }
        return materialBaseService.stockOut(materialBase) > 0 ? R.error("出库错误") : R.ok();
    }

    /**
     * 领料单编制完毕后，提交审核
     *
     * @return
     */
    @AutoLog(value = "提交审核", busModule = BusModule.LLD)
    @NonBusinessParamValid
    @RequestMapping("/commitApprove")
    @RequiresPermissions("spareMater:save")
    @ResponseBody
    public R commitApprove(@Validated @RequestBody SpareMaterialBaseApproveParam approveParam, BindingResult
            bindingResult) {
        MaterialBaseEntity materialBase = materialBaseService.queryObject(approveParam.getId());
        // 校验领料单是否存在
        if (materialBase == null) {
            return R.error("领料单不存在,请确认!");
        }
        // 只有新建工单才可以提交审核
        if (materialBase.getProgress() != MaterialBaseProgress.NEW && materialBase.getProgress() != MaterialBaseProgress.NOT_PASSED) {
            return R.error("只有新建工单才可以提交审核!");
        }
        // 校验下是否已添加备件
        List<MaterialRecordEntity> materialRecords = materialRecordService.queryByMater(approveParam.getId());
        if (CollectionUtil.isEmpty(materialRecords)) {
            return R.error("请在领料单添加备件后再提交审核!");
        }
        // 校验审批人是否存在
        SysUserEntity user = userService.queryObject(approveParam.getApproverId());
        if (user == null) {
            return R.error("审批用户不存在，请确认!");
        }
        materialBase.setApproverUser(user);
        // 设置室主任审批人:这个ID是长安认证中心的用户ID
        materialBase.setApproverUnionId(user.getUnionId());
        return sparepartMaterialBaseManager.commitApprove(materialBase) ? R.ok() : R.error();
    }


    /**
     * 由于之前存在领料单问题，导致
     * 如果ERMS系统处于审核中的领料单是否在OA上已处理完毕
     *
     * @return
     */
    @RequestMapping("/checkOver")
    @ResponseBody
    public R check(@RequestParam String id) {
        MaterialBaseEntity materialBase = materialBaseService.queryObject(id);
        // 校验领料单是否存在
        if (materialBase == null) {
            return R.error("领料单不存在,请确认!");
        }
        /*
            校验ERMS系统处于审核中的领料单是否在OA上已处理完毕
         */
        // 已出库、已关闭、已取消的领料单无需校验
        Integer progress = materialBase.getProgress();
        if (!NumberUtil.equals(progress, MaterialBaseProgress.WAIT_APPROVE)) {
            return R.error("领料单已出库、已关闭或已取消，请勿重复操作！");
        }
        if (StrUtil.isEmpty(materialBase.getProcInstId())) {
            return R.error("当前领料单尚未审批过！");
        }
        BPMProcessInstance processInstance = workFlowManager.getByProcInstId(materialBase.getProcInstId());
        if (processInstance == null) {
            return R.error("流程实例不存在，请确认！");
        }
        int state = processInstance.getState();
        if (state == 5) {
            // 执行出库
            materialBaseService.stockOut(materialBase);
            // 2、如果是维修领料的话，需要生成备件换件记录
            if (NumberUtil.equals(MaterialBaseConst.REPAIR_MATERIAL, materialBase.getMaterialType())) {
                sparePartConsumRecordService.generateByRepairMaterial(materialBase);
            } else if (NumberUtil.equals(MaterialBaseConst.MAINTENANCE_MATERIAL, materialBase.getMaterialType())) {
                sparePartConsumRecordService.generateByPmMaterial(materialBase);
            }
            // 生成流程审批信息，默认生成最后一个环节的
            SysOaProcessEntity processRecord = new SysOaProcessEntity();
            processRecord.setProcessInstId(materialBase.getProcInstId());
            processRecord.setWorkitemName("5.库管组长确认");
            processRecord.setBusId(materialBase.getId());
            processRecord.setBusType("MATERIAL");
            processRecord.setProcessWorkitemId("11111111111");
            processRecord.setState(1);
            processRecord.setApprover("ce3d1846d9ea41d7a53808e37598af15");
            processService.save(processRecord);
        }
        return R.ok();
    }

    /**
     * 取消领料审核
     *
     * @return
     */
    @AutoLog(value = "取消领料", busModule = BusModule.LLD)
    @LimitSubmit(key = "cancelSpareMater:%s")
    @RequestMapping("/cancel")
    @RequiresPermissions("spareMater:save")
    @ResponseBody
    public R cancel(@RequestParam String id) {
        MaterialBaseEntity materialBase = materialBaseService.queryObject(id);
        // 校验领料单是否存在
        if (materialBase == null) {
            return R.error("领料单不存在,请确认!");
        }
        // 只可以取消自己发起的领料单
        if (!ShiroUtils.getUserId().equals(materialBase.getPicker())) {
            return R.error("只可以取消自己发起的领料申请！");
        }
        // 已出库、已关闭、已取消的领料单不允许取消
        Integer progress = materialBase.getProgress();
        if (CollectionUtil.newArrayList(MaterialBaseProgress.END_OUTBOUND, MaterialBaseProgress.CLOSE, MaterialBaseProgress.CANCEL).contains(progress)) {
            return R.error("领料单已出库、已关闭或已取消，请勿重复操作！");
        }
        // 取消领料
        return sparepartMaterialBaseManager.cancel(materialBase) ? R.ok() : R.error();
    }

    /**
     * 失效已出库的领料单据
     *
     * @return
     */
    @AutoLog(value = "失效领料单", busModule = BusModule.LLD)
    @LimitSubmit(key = "invalidSpareMater:%s")
    @RequestMapping("/invalid")
    @RequiresPermissions("spareMater:invalid")
    @ResponseBody
    public R invalid(@RequestParam String id) {
        MaterialBaseEntity materialBase = materialBaseService.queryObject(id);
        // 校验领料单是否存在
        if (materialBase == null) {
            return R.error("领料单不存在,请确认!");
        }
        // 已出库、已关闭、已取消的领料单不允许取消
        Integer progress = materialBase.getProgress();
        if (!NumberUtil.equals(MaterialBaseProgress.END_OUTBOUND, progress)) {
            return R.error("只可以无效[ 已出库 ]的备件领料单据！");
        }
        // 取消领料
        return sparepartMaterialBaseManager.invalid(materialBase) ? R.ok() : R.error();
    }

    /**
     * 保存
     */
    @AutoLog(value = "保存", busModule = BusModule.LLD)
    @RequestMapping("/save")
    @RequiresPermissions("spareMater:save")
    @ResponseBody
    public R save(@RequestBody MaterialBaseEntity materialBase) {
        Integer materialType = materialBase.getMaterialType();
        // 如果是维修领料的话，需要做以下校验并关联产线
        if (MaterialBaseConst.REPAIR_MATERIAL.equals(materialType)) {
            // 维修工单号必填
            String jobCode = materialBase.getJobCode();
            if (StrUtil.isEmpty(jobCode)) {
                return R.error("维修领料时维修工单号必填！");
            }
            // 校验维修工单是否存在
            DevRepairRecordEntity repairRecord = devRepairRecordService.queryObjectByRepairCode(jobCode);
            if (repairRecord == null) {
                return R.error("非法维修工单编号！");
            }
            materialBase.setLineCode(repairRecord.getDevProductCode());
        } else if (MaterialBaseConst.MAINTENANCE_MATERIAL.equals(materialType)) {
            // 维修工单号必填
            String jobCode = materialBase.getJobCode();
            if (StrUtil.isEmpty(jobCode)) {
                return R.error("维修领料时维修工单号必填！");
            }
            // 校验维修工单是否存在
            DevMaintenanceTicketEntity pmTicket = pmTicketService.queryObjectByRepairCode(jobCode);
            if (pmTicket == null) {
                return R.error("非法维修工单编号！");
            }
            materialBase.setLineCode(pmTicket.getDevProductCode());
        } else if (MaterialBaseConst.COMMON_MATERIAL.equals(materialType)) {
            if (StrUtil.isEmpty(materialBase.getLineCode())) {
                return R.error("线边库时，必须录入领用的生产线！");
            }
        }
        return materialBaseService.save(materialBase) > 0 ? R.ok() : R.error("新增领料单失败");
    }

    /**
     * 修改
     */
    @AutoLog(value = "修改", busModule = BusModule.LLD)
    @RequestMapping("/update")
    @RequiresPermissions("spareMater:update")
    @ResponseBody
    public R update(@RequestBody MaterialBaseEntity materialBase) {
        materialBaseService.update(materialBase);

        return R.ok();
    }

    /**
     * 删除
     */
    @AutoLog(value = "删除", busModule = BusModule.LLD)
    @RequestMapping("/delete")
    @RequiresPermissions("spareMater:delete")
    @ResponseBody
    public R delete(@RequestBody String[] ids) {
        materialBaseService.deleteBatch(ids);

        return R.ok();
    }

    /**
     * 查看所有列表
     */
    @RequestMapping("/queryAll")
    @ResponseBody
    public R queryAll(@RequestParam Map<String, Object> params) {

        List<MaterialBaseEntity> list = materialBaseService.queryList(params);

        return R.ok().put("list", list);
    }
}
